package com.rolfhoward.audio.manager

import android.content.Context
import android.media.AudioFormat
import android.media.AudioRecord
import android.media.MediaRecorder
import android.os.Environment
import java.io.File
import java.io.FileOutputStream
import java.io.RandomAccessFile

/**
 *@author wuqiubin
 *@date 2022/9/2
 *@Describe 懒汉式单例类
 */
class AudioRecordManager private constructor(){

    private var sampleRateInHz = 0
    private var channelConfig = 0
    private var audioFormat = 0
    private var pcmFile: File? = null
    private var mAudioRecord: AudioRecord? = null
    private val bufferSize = 1024
    private var isRecording = false
    private var context: Context? = null

    companion object{
        private var instance: AudioRecordManager? = null
        @Synchronized
        fun get():AudioRecordManager{
            if (instance == null){
                instance = AudioRecordManager()
            }
            return instance!!
        }
    }

    fun init(context: Context) {
        this.context = context
        sampleRateInHz = 44100 //音频采样率，采用常用采样率44.1kHZ
        channelConfig = AudioFormat.CHANNEL_IN_MONO //音频录制声道，CHANNEL_IN_MONO 单声道 CHANNEL_IN_STEREO 双声道
        audioFormat = AudioFormat.ENCODING_PCM_16BIT //采样精度，位宽 通常采用16bit
        val bufferSize = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat)
        this.mAudioRecord = AudioRecord(
            MediaRecorder.AudioSource.MIC,
            sampleRateInHz,
            channelConfig,
            audioFormat,
            bufferSize
        )
        pcmFile = File(context.getExternalFilesDir(Environment.DIRECTORY_MUSIC), "record.pcm")

    }

    /**
     * 开始录制音频
     * */
    fun startRecording(){
        //判断录音文件是否存在，如果存在则删除原录音文件
        if (this.pcmFile?.exists() == true){
            pcmFile?.delete()
        }
        //是否录制状态 -开始录制
        isRecording = true
        //录制字节缓冲区大小
        val buffer = ByteArray(bufferSize)
        //开始录制
        mAudioRecord?.startRecording()
        //开启线程写入文件
        Thread {
            var fileOutputStream: FileOutputStream? = null
            try {
                fileOutputStream = FileOutputStream(pcmFile)
                if (null != fileOutputStream) {
                    while (true) {
                        if (isRecording) {
                            //循环写入PCM文件中
                            mAudioRecord?.read(buffer, 0, bufferSize)
                            fileOutputStream.write(buffer)
                        }else{
//                            //录制完成增加wav头
//                            val audioByteLen = pcmFile?.length()?.minus(8L) ?: 0L
//                            val wavByteLen = audioByteLen + 36
//                            var header = addWavHeader(audioByteLen, wavByteLen, sampleRateInHz,
//                                channelConfig, audioFormat
//                            )
//                            try {
//                                val wavFile = RandomAccessFile(pcmFile!!, "rw")
//                                wavFile!!.seek(0L)
//                                wavFile.write(header)
//                                wavFile.close()
//                            } catch (var12: Throwable) {
//                            }
                            break
                        }
                    }
                    fileOutputStream.flush()
                }
            } catch (e: Exception) {
                e.printStackTrace()
            } finally {
                fileOutputStream?.close()
            }

        }.start()
    }

    /**结束录制音频**/
    fun stopRecording(callback:(String) -> Unit){
        isRecording = false
        mAudioRecord?.stop()
        callback(pcmFile?.absolutePath!!)
    }

    /**释放音频资源**/
    fun release() {
        mAudioRecord?.release()
        mAudioRecord = null
    }

    private fun addWavHeader(
        audioByteLen: Long,
        wavByteLen: Long,
        sampleRateInHz: Int,
        channelConfig: Int,
        audioFormat: Int
    ): ByteArray{
        val header = ByteArray(44)
        // RIFF/WAVE header chunk
        header[0] = 'R'.toByte()
        header[1] = 'I'.toByte()
        header[2] = 'F'.toByte()
        header[3] = 'F'.toByte()
        header[4] = ((wavByteLen and 0xff).toByte())
        header[5] = ((wavByteLen shr 8 and 0xff).toByte())
        header[6] = ((wavByteLen shr 16 and 0xff).toByte())
        header[7] = ((wavByteLen shr 24 and 0xff).toByte())

        //WAVE
        header[8] = 'W'.toByte()
        header[9] = 'A'.toByte()
        header[10] = 'V'.toByte()
        header[11] = 'E'.toByte()

        // 'fmt ' chunk 4 个字节
        header[12] = 'f'.toByte()
        header[13] = 'm'.toByte()
        header[14] = 't'.toByte()
        header[15] = ' '.toByte()
        // 4 bytes: size of 'fmt ' chunk（格式信息数据的大小 header[20] ~ header[35]）
        header[16] = 16
        header[17] = 0
        header[18] = 0
        header[19] = 0
        // format = 1 编码方式
        header[20] = 1
        header[21] = 0
        // 声道数目
        val channelSize = if (channelConfig === android.media.AudioFormat.CHANNEL_IN_MONO) 1 else 2
        header[22] = channelSize.toByte()
        header[23] = 0
        // 采样频率
        header[24] = ((sampleRateInHz and 0xff).toByte())
        header[25] = ((sampleRateInHz shr 8 and 0xff).toByte())
        header[26] = ((sampleRateInHz shr 16 and 0xff).toByte())
        header[27] = ((sampleRateInHz shr 24 and 0xff).toByte())
        // 每秒传输速率
        val byteRate: Int = audioFormat * sampleRateInHz * channelSize
        header[28] = (byteRate and 0xff).toByte()
        header[29] = (byteRate shr 8 and 0xff).toByte()
        header[30] = (byteRate shr 16 and 0xff).toByte()
        header[31] = (byteRate shr 24 and 0xff).toByte()
        // block align 数据库对齐单位，每个采样需要的字节数
        header[32] = (2 * 16 / 8).toByte()
        header[33] = 0
        // bits per sample 每个采样需要的 bit 数
        header[34] = 16
        header[35] = 0

        //data chunk
        header[36] = 'd'.toByte()
        header[37] = 'a'.toByte()
        header[38] = 't'.toByte()
        header[39] = 'a'.toByte()
        // pcm字节数
        header[40] = ((audioByteLen and 0xff).toByte())
        header[41] = ((audioByteLen shr 8 and 0xff).toByte())
        header[42] = ((audioByteLen shr 16 and 0xff).toByte())
        header[43] = ((audioByteLen shr 24 and 0xff).toByte())

        return header
    }
}